package JobManagementUtils;

/*
This file is part of Open Grid Job Management System (OGJMS).

OGJMS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

OGJMS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OGJMS.  If not, see <http://www.gnu.org/licenses/>.

The entire and newest source code can be found at http://code.google.com/p/ogjms/  
 */

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.axis.message.MessageElement;
import org.globus.axis.message.addressing.EndpointReferenceType;
import org.globus.axis.util.Util;
import org.globus.delegation.DelegationUtil;
import org.globus.gsi.CertUtil;
import org.globus.gsi.GSIConstants;
import org.globus.gsi.GlobusCredential;
import org.globus.gsi.OpenSSLKey;
import org.globus.gsi.bc.BouncyCastleCertProcessingFactory;
import org.globus.gsi.bc.BouncyCastleOpenSSLKey;
import org.globus.wsrf.WSRFConstants;
import org.globus.wsrf.impl.security.authentication.Constants;
import org.globus.wsrf.impl.security.authorization.HostAuthorization;
import org.globus.wsrf.impl.security.descriptor.ClientSecurityDescriptor;
import org.globus.wsrf.utils.AddressingUtils;
import org.oasis.wsrf.properties.QueryExpressionType;
import org.oasis.wsrf.properties.QueryResourcePropertiesResponse;
import org.oasis.wsrf.properties.QueryResourceProperties_Element;
import org.oasis.wsrf.properties.QueryResourceProperties_PortType;
import org.oasis.wsrf.properties.WSResourcePropertiesServiceAddressingLocator;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Utils {
	public static final int TERM_TIME = 100;
	final static WSResourcePropertiesServiceAddressingLocator locator = new WSResourcePropertiesServiceAddressingLocator();

	public static EndpointReferenceType delegateCredential(String factoryUrl,
			String proxyFile) throws Exception {
		ClientSecurityDescriptor desc = new ClientSecurityDescriptor();
		// Credential to sign with, assuming default credential
		GlobusCredential credential = new GlobusCredential(proxyFile);// GlobusCredential.getDefaultCredential();
		desc.setGSISecureConv(Constants.ENCRYPTION);
		Util.registerTransport();
		desc.setGSISecureTransport(GSIConstants.ENCRYPTION);

		desc.setAuthz(HostAuthorization.getInstance());

		// lifetime in seconds
		int lifetime = TERM_TIME * 60;

		// Get the public key to delegate on.
		EndpointReferenceType delegEpr = AddressingUtils
				.createEndpointReference(factoryUrl, null);
		X509Certificate[] certsToDelegateOn = DelegationUtil
				.getCertificateChainRP(delegEpr, desc);
		X509Certificate certToSign = certsToDelegateOn[0];
		return DelegationUtil.delegate(factoryUrl, credential, certToSign,
				lifetime, false, desc);
	}

	public static void createProxy(String proxyFile, String certFile,
			String keyFile, String password) throws Exception {
		X509Certificate certificate;
		GlobusCredential globusCredential;
		PrivateKey userKey;
		int proxyType;
		int lifetime = 3600 * 60;

		System.out.println("creating user proxy ... [BEGIN]");

		System.out.println("\tloading user certificate ... [BEGIN]");
		InputStream usercertInput = new FileInputStream(new File(certFile));
		InputStream userkeyInput = new FileInputStream(new File(keyFile));

		certificate = CertUtil.loadCertificate(usercertInput);// this.certFile);
		System.out.println(certificate == null ? "cert null" : "cert not null");
		System.out.println("\t\tUser Identity: "
				+ certificate.getSubjectDN().getName());
		System.out.println("\tloading user certificate ... [DONE]");

		System.out.println("\tloading user key ... [BEGIN]");
		OpenSSLKey sslKey = new BouncyCastleOpenSSLKey(userkeyInput);
		if (true == sslKey.isEncrypted()) {
			System.out.println("\t\tuser key is encrypted");
			sslKey.decrypt(password);
		}
		userKey = sslKey.getPrivateKey();
		System.out.println("\tloading user key ... [DONE]");

		System.out.println("\tcreating the proxy file ... [BEGIN]");
		// this.proxyType = GSIConstants.GSI_2_PROXY;
		proxyType = GSIConstants.GSI_4_IMPERSONATION_PROXY;
		BouncyCastleCertProcessingFactory factory = BouncyCastleCertProcessingFactory
				.getDefault();

		globusCredential = factory.createCredential(
				new X509Certificate[] { certificate }, userKey,
				JobManagementConstants.ENCRYPTION_BITS, lifetime, proxyType);
		System.out.println("\t\tproxy created -> valid until: "
				+ globusCredential.getCertificateChain()[0].getNotAfter());
		System.out.println("\t\twriting proxy file ... ");
		OutputStream out = null;
		try {
			out = new FileOutputStream(proxyFile);
			globusCredential.save(out);
			System.out
					.println("\t\tsetting appropriate proxy file permissions ... ");
			setPermissions(proxyFile);
		} catch (IOException ioex) {
			System.err
					.println("failed to save proxy file and to init proxy ... :(");
			System.err.println("reason: " + ioex.getMessage());
			System.out.println("\tcreating the proxy file ... [FAILED]");
			System.out.println("creating user proxy ... [FAILED]");
			if (null != out) {
				out.close();
			}
			return;
		} finally {
			if (null != out) {
				try {
					out.close();
				} catch (Exception e) {
					throw e;
				}
			}
		}

		System.out.println("\tcreating the proxy file ... [DONE]");

		System.out.println("creating user proxy ... [DONE]");
	}

	public void getGridInformation(String URL) { // to be getGridInfo in Utils
		try {

			QueryResourceProperties_PortType port = locator
					.getQueryResourcePropertiesPort(new URL(
							"https://stefan.grid:8443/wsrf/services/DefaultIndexService"));
			QueryResourcePropertiesResponse resp = port
					.queryResourceProperties(new QueryResourceProperties_Element(
							new QueryExpressionType(
									WSRFConstants.XPATH_1_DIALECT,
									"//*[local-name()='GLUECE']")));
			MessageElement[] elem = resp.get_any();
			for (int i = 0; i < elem.length; i++) {

				SAXParserFactory parserFact = SAXParserFactory.newInstance();
				SAXParser parser = parserFact.newSAXParser();
				System.out.println("XML Elements: ");
				DefaultHandler handler = new DefaultHandler() {
					public void startElement(String uri, String lName,
							String ele, Attributes attributes)
							throws SAXException {
						// print elements of xml
						System.out.println(ele.split(":")[1] + ":");
						for (int k = 0; k < attributes.getLength(); k++) {
							System.out.println("\t"
									+ attributes.getQName(k).split(":")[1]
									+ " = " + attributes.getValue(k));
						}
						System.out.println();
					}
				};
				parser.parse(new ByteArrayInputStream(elem[i].getAsString()
						.getBytes()), handler);

			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void setPermissions(String filename) throws Exception {
		String cmd = "chmod 600 " + filename;
		Process setter = Runtime.getRuntime().exec(cmd);
		setter.waitFor();
	}

}
